#include "../inc/brain.h"
#include <stdarg.h>
#include <fstream>
#include <sstream>

Brain::Brain()
{
	mesh = NULL;
	map = NULL;
	sulcis = NULL;
	gyris = NULL;
	link.clear();
}

Brain::Brain(const Brain &_b)
{
	mesh = _b.mesh;
	map = _b.map;
	sulcis = _b.sulcis;
	gyris = _b.gyris;
	link = _b.link;
}

Brain::~Brain()
{
	/*
	mesh->clear();
	map->clear();
	Theese instructions would destroy the mesh and the map of the brain. So if other pointers point on this brain or this map it is dangerous !
	*/
	link.clear();
}

Brain& Brain::operator = ( const Brain& _b )
{
	mesh = _b.mesh;
	map = _b.map;
	sulcis = _b.sulcis;
	gyris = _b.gyris;
	link = _b.link;
	
	return *this;
}

Mesh* Brain::getMesh()
{
	return mesh;
}

Map* Brain::getMap()
{
	return map;
}

SegmentTree* Brain::getSulcis()
{
	return sulcis;
}

SegmentTree* Brain::getGyris()
{
	return gyris;
}

vector<Link> Brain::getLink()
{
	return link;
}

vector<int> Brain::getScores()
{
	return scores;
}

int Brain::getIScore(int _i)
{
	return scores[_i];
}

void Brain::setMesh(Mesh* _mesh)
{
	mesh = _mesh;
}

void Brain::setMap(Map* _map)
{
	map = _map;
}

void Brain::setSulcis(SegmentTree *_sulcis)
{
	sulcis = _sulcis;
}

void Brain::setGyris(SegmentTree *_gyris)
{
	gyris = _gyris;
}

void Brain::setLink ( vector<Link> _v )
{
	link = _v;
}

void Brain::setScores(vector<int> _scores)
{
	scores = _scores;
}

void Brain::setIScore(int _i, int _score)
{
	scores[_i] = _score;
}

void Brain::clear()
{
	if ( mesh != NULL )
		mesh->clear();
	
	if ( map != NULL )
		map->clear();
	
	link.clear();
	
	if ( sulcis != NULL )
		sulcis->clear();
	
	if ( gyris != NULL )
		gyris->clear();
	
	sulcis = NULL;
	gyris = NULL;
}

int Brain::save( char* _path)
{
	/* Saving the mesh in a wavefront obj format. */
	if ( mesh->saveOBJ( _path ) == -1 )
	{
		cout<<"Error while saving the file \""<<_path<<"\" : file can not be opened"<<endl;
		cout<<"Brain saving method returning -1"<<endl;
		return -1;
	}
	
	/* Opening the file to add the sulcis informations. */
	ofstream file ( _path, ios::app );
	
	if ( !file.is_open() )
	{
		cout<<"Error while saving the file \""<<_path<<"\" : file can not be opened"<<endl;
		cout<<"Brain saving method returning -1"<<endl;
		return -1;
	}
	
	/* For every ancester in the sulci tree. */
	int i = 0;
	for ( SegmentTree* it = sulcis ; it != NULL ; it = it->getBrother() )
	{
		/* Writing name line. */
		if ( it->getName() == "" )
		{
			/* Giving a name if the sulcus didn't have one. */
			file<<"n "<<"noName"<<i<<endl;
			i++;
		}
		
		else
			file<<"n "<<it->getName()<<endl;
		
		/* And color line. (the color is 0,0,0 by default. */
		file<<"c "<<it->getColor().getX()<<" "<<it->getColor().getY()<<" "<<it->getColor().getZ()<<endl;
		
		/* Writing the list of vertices componing the sulcus. */
		list<Vertex*> cpy = it->getSegment()->getVerts();
		for ( list<Vertex*>::iterator itVert = cpy.begin() ; itVert != cpy.end() ; itVert++ )
			file<<"sv "<<(*itVert)->getID()<<endl;
	}

	/* Closing file. */
	file.close();
	
	return 1;
}

int Brain::load(char *_path)
{
	/* Loading mesh. */
	mesh = new Mesh();
	if ( mesh->loadOBJ( _path ) == -1 )
	{
		cout<<"A problem occured during the loading of the brain's mesh."<<endl;
		cout<<"Brain loading method returning -1."<<endl;
		return -1;
	}
	mesh->computeNormals();
	mesh->normalize();
			
	ifstream file ( _path );
	
	if ( !file.is_open() )
	{
		cout<<"Error while loading the file \""<<_path<<"\" : file can not be opened"<<endl;
		cout<<"Brain loading method returning -1"<<endl;
		return -1;
	}
	
	/* ___________________________________________________________________________________ So that the stream is at the end of the mesh definition.. not elegant at all, methods have to be re written !! _____ */
	char		type[255];
	char		line[255];
	file.get( type, 250, ' ' );
	while ( strcmp ( type, "n" ) != 0 && file.good() )
	{
		file.getline( line, 500 );
		file.get( type, 250, ' ' );
	}
	/* _________________________________________________________________________________________________________________________________________________________________________________________________________ */
			
	while ( file.good() )
	{
		/* The stream is now after the letter n of the first sulcus name. */
		/* Creation of a new sulcus. */
		SegmentTree* sulcus = new SegmentTree();
		Vector3D color;
		char name[500];
		char colorLine[500];
		
		/* We read the name of the sulcus. */
		file.getline( name, 500 );
		
		/* Set the name of the sulcus. */
		sulcus->setName( name );
		
		/* Read the color line. */
		file.getline( colorLine, 500 );
		
		/* Declaring an iss stream to read word per word the color line. */
		istringstream	iss ( colorLine, istringstream::in );
		string colorWord;
		iss>>colorWord;
		if ( colorWord != "c" )
		{
			cout<<"J'ai lu \""<<colorWord<<"\""<<endl;
			cout<<"Error while reading the brain file."<<endl;
			cout<<"Loading method returning -1."<<endl;
			return -1;
		}
		
		/* Read the red component. */
		iss>>colorWord;
		color.setX( atof( colorWord.c_str() ) );
		
		/* Read the green component. */
		iss>>colorWord;
		color.setY( atof( colorWord.c_str() ) );
		
		/* Read the blue component. */
		iss>>colorWord;
		color.setZ( atof( colorWord.c_str() ) );
		
		/* Set the red component of the sulcus. */
		sulcus->setColor( color );
		
		/* Creating a segment which will contain the sulcus vertices. */
		Segment*		segment = new Segment();
		
		file>>type;
		while ( file.good() && strcmp ( type, "sv" ) == 0 )
		{
			/* Read the id of the vertex. */
			int ID;
			file>>ID;
			
			/* Adding this vertex to the segment. */
			segment->addVert( mesh->getIVert(ID) );
			
			if ( file.good() )
				file>>type;
		}
		
		/* Setting the sulcus vertices. */
		sulcus->setSegment( segment );
		
		/* Finally adding the created node (sulcus) to the brain. */
		if ( sulcis == NULL )
			sulcis = sulcus;
		
		else
			sulcis->addBrother( sulcus );
	}
	
	file.close();
	
	return 1;
}

vector<Link> Brain::linkBy_Intersection( Brain _b )
{
	vector<Link> rslt;
	
	/* We computes one matching list per ancester of the brain tree. */
	for ( SegmentTree* it = sulcis ; it != NULL ; it = it->getBrother() )
	{
		Link toAdd;
		SegmentTreeList liste;
		
		toAdd.setNode( (it) );
		
		liste.getMatchBy_Intersection( it, _b.sulcis );
		toAdd.setMatch( liste );
		
		rslt.push_back(toAdd);
	}
	
	return rslt;
}

vector<Link> Brain::linkBy_Distance(Brain _b, int _distMax)
{
	vector<Link> rslt;
	
	/* We computes one matching list per ancester of the brain tree. */
	for ( SegmentTree* it = sulcis ; it != NULL ; it = it->getBrother() )
	{
		Link toAdd;
		SegmentTreeList liste;
		
		toAdd.setNode( (it) );
		
		liste.getMatchBy_Distance( it, _b.sulcis, mesh, _distMax );
		toAdd.setMatch( liste );
		
		rslt.push_back(toAdd);
	}
	
	return rslt;
}

vector<Link> Brain::linkBy_Depth(Brain _b, int _distMax)
{
	vector<Link> rslt;
	
	/* We computes one matching list per ancester of the brain tree. */
	for ( SegmentTree* it = sulcis ; it != NULL ; it = it->getBrother() )
	{
		Link toAdd;
		SegmentTreeList liste;
		
		toAdd.setNode( (it) );
		
		liste.getMatchBy_Depth( it, _b.sulcis, _distMax );
		toAdd.setMatch( liste );
		
		rslt.push_back(toAdd);
	}
	
	return rslt;
}

vector<Link> Brain::linkBy_Area(Brain _b, double _distMax)
{
	vector<Link> rslt;
	double sourceArea = mesh->triangulatedArea();
	double targetArea = _b.mesh->triangulatedArea();
	
	/* We computes one matching list per ancester of the brain tree. */
	for ( SegmentTree* it = sulcis ; it != NULL ; it = it->getBrother() )
	{
		Link toAdd;
		SegmentTreeList liste;
		
		toAdd.setNode( (it) );
		
		liste.getMatchBy_Areas( it, mesh, sourceArea, _b.sulcis, _b.mesh, targetArea,  _distMax );
		toAdd.setMatch( liste );
		
		rslt.push_back(toAdd);
	}
	
	return rslt;
}

vector<Link> Brain::linkBy_BBoxBotX(Brain _b, int _distMax)
{
	vector<Link>	rslt;
	BoundingBox		sourceMeshBBox;
	BoundingBox		targetMeshBBox;
	
	sourceMeshBBox.create( mesh );
	targetMeshBBox.create( _b.getMesh() );
	
	/* We computes one matching list per ancester of the brain tree. */
	for ( SegmentTree* it = sulcis ; it != NULL ; it = it->getBrother() )
	{
		Link toAdd;
		SegmentTreeList liste;
		
		toAdd.setNode( (it) );
		
		liste.getMatchBy_BoundingBoxBotX( it, sourceMeshBBox, _b.getSulcis(), targetMeshBBox, _distMax );
		toAdd.setMatch( liste );
		
		rslt.push_back(toAdd);
	}
	
	return rslt;
}

vector<Link> Brain::linkBy_BBoxTopX(Brain _b, int _distMax)
{
	vector<Link>	rslt;
	BoundingBox		sourceMeshBBox;
	BoundingBox		targetMeshBBox;
	
	sourceMeshBBox.create( mesh );
	targetMeshBBox.create( _b.getMesh() );
	
	/* We computes one matching list per ancester of the brain tree. */
	for ( SegmentTree* it = sulcis ; it != NULL ; it = it->getBrother() )
	{
		Link toAdd;
		SegmentTreeList liste;
		
		toAdd.setNode( (it) );
		
		liste.getMatchBy_BoundingBoxTopX( it, sourceMeshBBox, _b.getSulcis(), targetMeshBBox, _distMax );
		toAdd.setMatch( liste );
		
		rslt.push_back(toAdd);
	}
	
	return rslt;
}

vector<Link> Brain::linkBy_BBoxBotY(Brain _b, int _distMax)
{
	vector<Link>	rslt;
	BoundingBox		sourceMeshBBox;
	BoundingBox		targetMeshBBox;
	
	sourceMeshBBox.create( mesh );
	targetMeshBBox.create( _b.getMesh() );
	
	/* We computes one matching list per ancester of the brain tree. */
	for ( SegmentTree* it = sulcis ; it != NULL ; it = it->getBrother() )
	{
		Link toAdd;
		SegmentTreeList liste;
		
		toAdd.setNode( (it) );
		
		liste.getMatchBy_BoundingBoxBotY( it, sourceMeshBBox, _b.getSulcis(), targetMeshBBox, _distMax );
		toAdd.setMatch( liste );
		
		rslt.push_back(toAdd);
	}
	
	return rslt;
}

vector<Link> Brain::linkBy_BBoxTopY(Brain _b, int _distMax)
{
	vector<Link>	rslt;
	BoundingBox		sourceMeshBBox;
	BoundingBox		targetMeshBBox;
	
	sourceMeshBBox.create( mesh );
	targetMeshBBox.create( _b.getMesh() );
	
	/* We computes one matching list per ancester of the brain tree. */
	for ( SegmentTree* it = sulcis ; it != NULL ; it = it->getBrother() )
	{
		Link toAdd;
		SegmentTreeList liste;
		
		toAdd.setNode( (it) );
		
		liste.getMatchBy_BoundingBoxTopY( it, sourceMeshBBox, _b.getSulcis(), targetMeshBBox, _distMax );
		toAdd.setMatch( liste );
		
		rslt.push_back(toAdd);
	}
	
	return rslt;
}

vector<Link> Brain::linkBy_BBoxBotZ(Brain _b, int _distMax)
{
	vector<Link>	rslt;
	BoundingBox		sourceMeshBBox;
	BoundingBox		targetMeshBBox;
	
	sourceMeshBBox.create( mesh );
	targetMeshBBox.create( _b.getMesh() );
	
	/* We computes one matching list per ancester of the brain tree. */
	for ( SegmentTree* it = sulcis ; it != NULL ; it = it->getBrother() )
	{
		Link toAdd;
		SegmentTreeList liste;
		
		toAdd.setNode( (it) );
		
		liste.getMatchBy_BoundingBoxBotZ( it, sourceMeshBBox, _b.getSulcis(), targetMeshBBox, _distMax );
		toAdd.setMatch( liste );
		
		rslt.push_back(toAdd);
	}
	
	return rslt;
}

vector<Link> Brain::linkBy_BBoxTopZ(Brain _b, int _distMax)
{
	vector<Link>	rslt;
	BoundingBox		sourceMeshBBox;
	BoundingBox		targetMeshBBox;
	
	sourceMeshBBox.create( mesh );
	targetMeshBBox.create( _b.getMesh() );
	
	/* We computes one matching list per ancester of the brain tree. */
	for ( SegmentTree* it = sulcis ; it != NULL ; it = it->getBrother() )
	{
		Link toAdd;
		SegmentTreeList liste;
		
		toAdd.setNode( (it) );
		
		liste.getMatchBy_BoundingBoxTopZ( it, sourceMeshBBox, _b.getSulcis(), targetMeshBBox, _distMax );
		toAdd.setMatch( liste );
		
		rslt.push_back(toAdd);
	}
	
	return rslt;
}

vector<Link> Brain::linkBy_BBoxX(Brain _b, int _distMax)
{
	vector<Link>	rslt;
	BoundingBox		sourceMeshBBox;
	BoundingBox		targetMeshBBox;
	
	sourceMeshBBox.create( mesh );
	targetMeshBBox.create( _b.getMesh() );
	
	/* We computes one matching list per ancester of the brain tree. */
	for ( SegmentTree* it = sulcis ; it != NULL ; it = it->getBrother() )
	{
		Link toAdd;
		SegmentTreeList liste;
		
		toAdd.setNode( (it) );
		
		liste.getMatchBy_BoundingBoxX( it, sourceMeshBBox, _b.getSulcis(), targetMeshBBox, _distMax );
		toAdd.setMatch( liste );
		
		rslt.push_back(toAdd);
	}
	
	return rslt;
}

vector<Link> Brain::linkBy_BBoxY(Brain _b, int _distMax)
{
	vector<Link>	rslt;
	BoundingBox		sourceMeshBBox;
	BoundingBox		targetMeshBBox;
	
	sourceMeshBBox.create( mesh );
	targetMeshBBox.create( _b.getMesh() );
	
	/* We computes one matching list per ancester of the brain tree. */
	for ( SegmentTree* it = sulcis ; it != NULL ; it = it->getBrother() )
	{
		Link toAdd;
		SegmentTreeList liste;
		
		toAdd.setNode( (it) );
		
		liste.getMatchBy_BoundingBoxY( it, sourceMeshBBox, _b.getSulcis(), targetMeshBBox, _distMax );
		toAdd.setMatch( liste );
		
		rslt.push_back(toAdd);
	}
	
	return rslt;
}

vector<Link> Brain::linkBy_BBoxZ(Brain _b, int _distMax)
{
	vector<Link>	rslt;
	BoundingBox		sourceMeshBBox;
	BoundingBox		targetMeshBBox;
	
	sourceMeshBBox.create( mesh );
	targetMeshBBox.create( _b.getMesh() );
	
	/* We computes one matching list per ancester of the brain tree. */
	for ( SegmentTree* it = sulcis ; it != NULL ; it = it->getBrother() )
	{
		Link toAdd;
		SegmentTreeList liste;
		
		toAdd.setNode( (it) );
		
		liste.getMatchBy_BoundingBoxZ( it, sourceMeshBBox, _b.getSulcis(), targetMeshBBox, _distMax );
		toAdd.setMatch( liste );
		
		rslt.push_back(toAdd);
	}
	
	return rslt;
}

void Brain::linkBy_Crtiteria(int _thresh, vector<Link>* _v, int _weight...)
{
	vector<Link>*		argLink = NULL;
	va_list				args;
	Vector3D			finalColor;
	string				finalName;
	
	/*
	 We compute for every source node the complete list of all the matched nodes in the different link arrays.
	*/
	for ( int i = 0 ; i < (int)_v->size() ; i++ )
	{
		SegmentTreeList	matchMax;
		int				scoreMax = -1;
		finalColor.clear();
		finalName.clear();
		
		/* All match will be, for each reference node, the list of all the node that was matched with the reference node in at least one arry of link. */
		SegmentTreeList		allMatch;
		
		/* We initialize all match to the matching list of the first link array given in parameter. */
		allMatch = (*_v)[i].getMatch();
		
		/* Creating the allMatch list : */
		va_start ( args, _weight );
		while ( ( argLink = va_arg ( args, vector<Link>* ) ) )
		{
			/* For each link array given in parameter. */
			/* Adding the different matches that are not yet in the allMatch list. */
			allMatch += (*argLink)[i].getMatch();
			
			/* Don't forget to read the weight. */
			va_arg ( args, int );
		}	
		va_end ( args );
		
		/*
		 Then we must calculate the score of every match in the list we have just computed.
		*/
		for ( list<SegmentTree*>::iterator it = allMatch.getBegin() ; it != allMatch.getEnd() ; it++ )
		{
			/* Each of them has a score initialized to 0. */
			int score = 0;
			
			/* Having a look at the differents link array given in parameter. */
			va_start ( args, _weight );
			while ( ( argLink = va_arg ( args, vector<Link>* ) ) )
			{
				int weight = va_arg ( args, int );
				
				if ( (*argLink)[i].getMatch().contains( (*it) ) )
				{
					score += weight;
				}
			}	
			va_end ( args );
			
			/*
			 Don't forget to take a look at the first link array given in parameter which is not a part of the argument list.
			*/
			if ( (*_v)[i].getMatch().contains( (*it) ) )
			{
				score += _weight;
			}
			
			/* Now comparing to the threshold and to the scoreMax. */
			if ( score > _thresh && score > scoreMax )
			{
				/* We found a better mtaching for the final match. */
				scoreMax = score;
				matchMax.clear();
				finalColor = (*it)->getColor();
				finalName = (*it)->getName();
				matchMax.addNode(*it);
			}
		}
		
		/* Setting the final match in the object's link array. */
		Link toAdd;
		toAdd.setNode( (*_v)[i].getNode() );
		toAdd.getNode()->setColor( finalColor );
		toAdd.getNode()->setName( finalName );
		toAdd.setMatch( matchMax );
		
		link.push_back( toAdd );
		
		/* Setting the score of the match. If no match has been found, scoreMax = -1 and so the final score. */
		scores.push_back( scoreMax );
	}
}

void Brain::improveLinks( Brain _target )
{
	/* For each link. */
	for ( int i = 0 ; i < (int)link.size() ; i++ )
	{
		/* If a match was found. */
		if ( scores[i] != -1 )
		{
			/* Variables to stock the final result (the improved one). */
			double scoreMax = scores[i];
			SegmentTreeList finalMatch;
			
			cout<<"Score a battre : "<<scoreMax<<endl;
			
			/* For every son of the matched segment. */
			for ( SegmentTree* son = link[i].getMatch().getFirst()->getSon() ; son != NULL ; son = son->getBrother() )
			{
				float score = link[i].getNode()->getMatchScore( mesh, son, _target.getMesh() );
				cout<<"\tScore des fils : "<<score<<endl;
				if ( score  > scoreMax )
				{
					scoreMax = score;
					finalMatch.clear();
					SegmentTree* toAdd;
					toAdd = son;
					toAdd->setColor( Vector3D(1,0,0));
					link[i].getNode()->setColor ( Vector3D(1,0,0) );
					finalMatch.addNode( son );
				}
			}
			
			/* If a better match has been found. */
			if ( !finalMatch.empty() )
			{
				link[i].setMatch ( finalMatch );
			}
		}
	}
}

void Brain::colorElements(float _r, float _g, float _b)
{
	if ( sulcis != NULL )
	{
		int nbEltsSulcis = sulcis->getNbBrothers()+1;
		int i = 0;
		
		for ( SegmentTree* it = sulcis ; it != NULL ; it = it->getBrother() )
		{
			if ( _r == -1 )
			{
				/* Value is the angle of the future color in the TLS format. */
				double value = (double)(i*360.0) / (double)nbEltsSulcis;
				it->setColor( tools_colorFromValue( DEGREES, value ) );
			}
			
			else
			{
				Vector3D color;
				color.set( _r, _g, _b );
				it->setColor( color );
			}
			
			i++;
		}
	}
	
	if ( gyris != NULL )
	{
		int nbEltsGyris = gyris->getNbBrothers()+1;
		
		int i = 0;
		
		for ( SegmentTree* it = gyris ; it != NULL ; it = it->getBrother() )
		{
			if ( _r == -1 )
			{
				/* Value is the angle of the future color in the TLS format. */
				double value = (double)(i*360.0) / (double)nbEltsGyris;
				it->setColor( tools_colorFromValue( DEGREES, value ) );
			}
			
			else
			{
				Vector3D color;
				color.set( _r, _g, _b );
				it->setColor( color );
			}
			
			i++;
		}
	}
}

void Brain::regroupSulcis(int _distMax)
{
	cout<<"Il manque la documentation de la methode regroup sulcis de la classe brain !!"<<endl;
		
	/* For each ancester of the tree. */
	for ( SegmentTree* it = sulcis ; it != NULL ; it = it->getBrother() )
	{
		bool stop = false;
		
		while ( !stop )
		{
			/* We create the list of all the nodes that the current one. */
			SegmentTreeList liste;
			liste.getMatchBy_Distance( it, sulcis, mesh, _distMax );
			
			if ( liste.empty() )
				stop = true;
			
			/* We merge every of the nodes that are in the list. i.e. which are not far away from the node. */
			for ( list<SegmentTree*>::iterator iter = liste.getBegin() ; iter != liste.getEnd() ; iter++ )
			{
				it->merge( (*iter) );
				
				if ( it == sulcis )
				{
					sulcis = SegmentTree::removeNode( sulcis, (*iter) );
					it = sulcis;
				}
				
				else
				{
					sulcis = SegmentTree::removeNode( sulcis, (*iter) );
				}
			}
		}
	}
}

void Brain::displaySurface(int _mode, float _r, float _g, float _b)
{
	mesh->display( _mode, _r, _g, _b );
}

void Brain::displaySulcis(int _mode, float _r, float _g, float _b)
{
	sulcis->displayBrotherhood( _mode, _r, _g, _b );
}

void Brain::displayLandMark(double _x, double _y, double _z, int _size)
{
	glDisable( GL_LIGHTING );
	glBegin ( GL_LINES );
	
	glColor3f( 1, 0, 0 );
	glVertex3f(_x, _y, _z );
	glVertex3f( _x + _size, _y, _z );
			
	glColor3f( 0, 1, 0 );
	glVertex3f(_x, _y, _z );
	glVertex3f(_x, _y + _size, _z );
	
	glColor3f( 0, 0, 1 );
	glVertex3f(_x, _y, _z );
	glVertex3f(_x, _y, _z + _size );
	
	glEnd();
	glEnable ( GL_LIGHTING );
}

void Brain::displayLinkReferences(int _mode, float _r, float _g, float _b)
{
	if ( _mode != PICKING )
	{
		for ( int i = 0 ; i < (int)link.size() ; i++ )
			link[i].getNode()->display( _mode, _r, _g, _b );
	}
	
	else
	{
		for ( int i = 0 ; i < (int)link.size() ; i++ )
		{
			glLoadName( i );
			link[i].getNode()->display( FACES, _r, _g, _b );
		}
	}	
}

void Brain::displayLinkMatched(int _mode, float _r, float _g, float _b)
{
	for ( int i = 0 ; i < (int)link.size() ; i++ )
		link[i].getMatch().display( _mode, _r, _g, _b );
}

SegmentTree* Brain::pickingNode(int _x, int _y, int _mode, TrackBall *_t)
{
	GLuint			selectBuf [1024];
	GLint			nbHits = 0;
	GLint			viewport[4];
	int				idPicked = -1;
	SegmentTree*	rslt = NULL;
	
	glGetIntegerv ( GL_VIEWPORT, viewport );
	glSelectBuffer ( 1024, selectBuf );
	glRenderMode ( GL_SELECT );
	
	glInitNames();
	glPushName(-10);
	
	glMatrixMode ( GL_PROJECTION );
	glPushMatrix();
	glLoadIdentity ();
	gluPickMatrix ((GLdouble) _x, (GLdouble) (viewport[3] - _y), 5, 5, viewport);
	
	
	gluPerspective(60.0f, (GLfloat) (viewport[2]-viewport[0])/(GLfloat) (viewport[3]-viewport[1]), 0.1f, 500.0f);
	glMatrixMode(GL_MODELVIEW);
	
	if ( _t != NULL )
		_t->displayBeginGL_GLUT();
	
	if ( _mode == SULCIS )
	{
		if ( sulcis != NULL )
			sulcis->displayBrotherhood( PICKING );	
		
		else
		{	cout<<"Sulcis tree of the brain you're trying to pick some sulcus is NULL"<<endl;
			return NULL;
		}
	}
	
	if ( _mode == GYRIS )
	{
		if ( gyris != NULL )
			gyris->displayBrotherhood( PICKING );
		
		else
		{	cout<<"Gyris tree of the brain you're trying to pick some gyrus is NULL"<<endl;
			return NULL;
		}
	}
	
	if ( _t != NULL )
		_t->displayEndGL_GLUT();
	
	glMatrixMode(GL_PROJECTION);
	glPopMatrix();
	glMatrixMode(GL_MODELVIEW);

	nbHits = glRenderMode ( GL_RENDER );
	
	if ( nbHits > 0 )
	{
		idPicked = tools_picking_IndexOfZMin( nbHits, selectBuf );
		
		/* Searching the idPicked th node in the tree. */
		if ( _mode == SULCIS )
		{
			/* No test for NULL, already done up. */
			rslt = sulcis;
			for ( int i = 0 ; i < idPicked ; i++ )
				rslt = rslt->getBrother();
		}
		
		if ( _mode == GYRIS )
		{
			/* No test for NULL, already done up. */
			rslt = gyris;
			for ( int i = 0 ; i < idPicked ; i++ )
				rslt = rslt->getBrother();
		}
	}
	
	return rslt;
}

SegmentTree* Brain::pickingLinkReference(int _x, int _y, TrackBall *_t)
{
	GLuint			selectBuf [1024];
	GLint			nbHits = 0;
	GLint			viewport[4];
	int				idPicked = -1;
	SegmentTree*	rslt = NULL;
	
	glGetIntegerv ( GL_VIEWPORT, viewport );
	glSelectBuffer ( 1024, selectBuf );
	glRenderMode ( GL_SELECT );
	
	glInitNames();
	glPushName(-10);
	
	glMatrixMode ( GL_PROJECTION );
	glPushMatrix();
	glLoadIdentity ();
	gluPickMatrix ((GLdouble) _x, (GLdouble) (viewport[3] - _y), 5, 5, viewport);
	
	
	gluPerspective(60.0f, (GLfloat) (viewport[2]-viewport[0])/(GLfloat) (viewport[3]-viewport[1]), 0.1f, 500.0f);
	glMatrixMode(GL_MODELVIEW);
	
	if ( _t != NULL )
		_t->displayBeginGL_GLUT();
	
	displayLinkReferences( PICKING );
	
	if ( _t != NULL )
		_t->displayEndGL_GLUT();
	
	glMatrixMode(GL_PROJECTION);
	glPopMatrix();
	glMatrixMode(GL_MODELVIEW);

	nbHits = glRenderMode ( GL_RENDER );
	
	if ( nbHits > 0 )
	{
		idPicked = tools_picking_IndexOfZMin( nbHits, selectBuf );
		rslt = link[idPicked].getNode();
	}
	
	return rslt;
}
